package jnzb.model.queue;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.table.AbstractTableModel;

import jnzb.control.AverageSpeedListener;
import jnzb.misc.StorageUnit;
import jnzb.model.nzb.NZB;

public class WaitingTableModel extends AbstractTableModel implements
		AverageSpeedListener {

	private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

	private LinkedList<NZB> queue = null;

	// Store the predicted finish times separately as the finish times are not
	// part of the underlying NZB model but are still derived from them. In
	// thisclass they are part of the model for the table
	private HashMap<NZB, String> predictedFinishTimes = new HashMap<NZB, String>();

	private static String[] COL_NAMES = new String[] { "NZB Name", "Size",
			"Fin @" };

	@Override
	public int getColumnCount() {
		return this.queue == null ? 0 : 3;
	}

	@Override
	public String getColumnName(int col) {
		return COL_NAMES[col];
	}

	@Override
	public int getRowCount() {
		// return queue.size();
		return this.queue == null ? 0 : this.queue.size();
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		String value = null;
		switch (columnIndex) {
		case 0:
			value = queue.get(rowIndex).getFilename();
			break;
		case 1:
			long size = queue.get(rowIndex).getSize();
			value = StorageUnit.of(size).format(size);
			break;
		case 2:
			value = "...";
			// Using the row index, pull out the appropriate NZB then use that
			// to get the predicted time out of the hashmap
			if (!predictedFinishTimes.isEmpty()) {
				String time = predictedFinishTimes.get(queue.get(rowIndex));
				if (time != null) {
					value = time;
				}
			}
			break;
		}
		return value;
	}

	/**
	 * Sets the reference to the NZB queue
	 * 
	 * @param queue
	 */
	public void setQueue(LinkedList<NZB> queue) {
		this.queue = queue;
	}

	public void queueChanged() {
		fireTableDataChanged();
	}

	/**
	 * Set the average speed so that we can use it in calculating the queue
	 * times
	 * 
	 * @see jnzb.control.AverageSpeedListener#setAverageSpeed(double)
	 */
	@Override
	public void setAverageSpeed(double avgSpeed) {
		calculatePredictedFinishTimes(avgSpeed);
		// Rather than fireTableDataChanged, do all rows as it keeps the
		// selection
		fireTableRowsUpdated(0, getRowCount());

	}

	/**
	 * Based on the average speed, calculate the finish times for each NZB in
	 * the queue
	 * 
	 * @param avgSpeed
	 */
	private void calculatePredictedFinishTimes(double avgSpeed) {
		Calendar c = new GregorianCalendar();
		Iterator<NZB> i = queue.iterator();
		int timeLeft = 0;
		while (i.hasNext()) {
			NZB nzb = i.next();
			// Get each time left and cumalatively add to the calendar to get a
			// time
			timeLeft = nzb.getTimeLeftAt(avgSpeed);
			c.add(Calendar.SECOND, timeLeft);
			// Format as string
			String finTime = sdf.format(c.getTime());
			// Add to hashtable
			predictedFinishTimes.put(nzb, finTime);
		}
	}

}
